package com.zkh.myutils.code;

import java.nio.charset.Charset;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

import com.zkh.myutils.utils.UtilsException;

public class RSAUtil {
	// 指定为RSA算法，不区分大小写
	private static final String KEY_ALGORITHM = "RSA";
	// 指定编码
	private static final Charset CHARSET = Charsets.UTF_8;
	// 密钥长度
	private static final int KEYSIZE = 1024;

	/**
     * RSA公钥加密
     * @param str 待加密字符串
     * @param publicKey 公钥
     * @return 密文
     */
	public static String encrypt(String str, String publicKey) throws Exception{
		return encrypt(str, publicKey, false);
	}
	
    /**
     * RSA公钥加密
     * @param str 待加密字符串
     * @param publicKey 公钥
     * @param isURL 是否要在链接中传递，如果为true，base64编码中将出现 - _ 字符，否则两个字符分别被 + / 替换。不传默认false
     * @return 密文
     */
	public static String encrypt(String str, String publicKey, boolean isURL) throws Exception {
		// base64编码的公钥
		byte[] decoded = CoderUtils.decodeBase64(publicKey, isURL);
		RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance(KEY_ALGORITHM).generatePublic(new X509EncodedKeySpec(decoded));
		// RSA加密
		Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
		cipher.init(Cipher.ENCRYPT_MODE, pubKey);
		// 返回
		return CoderUtils.encodeBase64(cipher.doFinal(str.getBytes(CHARSET)), isURL);
    }
	
	/**
	 * RSA私钥解密
	 * @param str 加密字符串
	 * @param privateKey 私钥
	 * @return
	 * @throws Exception
	 */
	public static String decrypt(String str, String privateKey) throws Exception {
		return decrypt(str, privateKey, false);
	}

	/**
	 * RSA私钥解密
	 * @param str 加密字符串
	 * @param privateKey 私钥
     * @param isURL 是否要在链接中传递，如果为true，base64编码中将出现 - _ 字符，否则两个字符分别被 + / 替换。不传默认false
	 */
	public static String decrypt(String str, String privateKey, boolean isURL) throws Exception {
		//64位解码加密后的字符串
		byte[] inputByte = CoderUtils.decodeBase64(str, isURL);
		//base64编码的私钥
		byte[] decoded = CoderUtils.decodeBase64(privateKey, isURL);
		RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance(KEY_ALGORITHM).generatePrivate(new PKCS8EncodedKeySpec(decoded));
		//RSA解密
		Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
		cipher.init(Cipher.DECRYPT_MODE, priKey);
		//返回
		return new String(cipher.doFinal(inputByte), CHARSET);
	}
	
	/**
	 * 随机生成一对加密对
	 * @return [公钥, 私钥]
	 */
	public static String[] genKeyPair() {
		return genKeyPair(false);
	}
	
	/**
	 * 随机生成一对加密对
	 * @return [公钥, 私钥]
     * @param isURL 是否要在链接中传递，如果为true，base64编码中将出现 - _ 字符，否则两个字符分别被 + / 替换。不传默认false
	 */
	public static String[] genKeyPair(boolean isURL) {
		try {
			// 获取生成器
			KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
			// 初始化
			keyPairGenerator.initialize(KEYSIZE);
			// 生成密匙对
			KeyPair keyPair = keyPairGenerator.generateKeyPair();
			// 获取公钥
			Key publicKey = keyPair.getPublic();
			// 获取私钥
			Key privateKey = keyPair.getPrivate();
			//返回
			return new String[]{CoderUtils.encodeBase64(publicKey.getEncoded(), isURL), CoderUtils.encodeBase64(privateKey.getEncoded(), isURL)};
		}catch(Exception e) {
			throw new UtilsException(e);
		}
	}
	
	/**
	 * 随机生成一对加密对并打印到控制台
	 */
	public static void printKeyPair() {
		printKeyPair(false);
	}
	
	/**
	 * 随机生成一对加密对并打印到控制台
     * @param isURL 是否要在链接中传递，如果为true，base64编码中将出现 - _ 字符，否则两个字符分别被 + / 替换。不传默认false
	 */
	public static void printKeyPair(boolean isURL) {
		//生成加密对
		String[] keyPair = genKeyPair(isURL);
		//打印
		System.err.println("公钥：" + keyPair[0]);
		System.err.println("私钥：" + keyPair[1]);
	}
}
